using System.Text;
using Luban.Datas;
using Luban.DataVisitors;
using Luban.Defs;
using Luban.Utils;
using Luban.Erlang.TemplateExtensions;

namespace Luban.Erlang.DataVisitors;

public class ToErlangLiteralVisitor : ToLiteralVisitorBase
{
    public static ToErlangLiteralVisitor Ins { get; } = new();
    
    public override string Accept(DString type)
    {
        if (type.Value != "")
        {
            return $"<<\"{DataUtil.EscapeString(type.Value)}\"/utf8>>";
        }
        else
        {
            return "<<>>";
        }
        
    }

    public string SysName(string name)
    {
        name = "Sys" + ErlangCommonTemplateExtension.ErlangPascal(name);
        return ErlangCommonTemplateExtension.ErlangSnake(name);
    }
    
    public override string Accept(DBean type)
    {
        var x = new StringBuilder();
        
        if (type.Type.IsAbstractType)
        {
            x.Append($"#{SysName(DataUtil.GetImplTypeName(type))}{{");
        }
        else
        {
            x.Append($"#{SysName(type.Type.Name)}{{");
        }

        int index = 0;
        foreach (var f in type.Fields)
        {
            var defField = type.ImplType.HierarchyFields[index++];
            if (f == null || (!type.Type.IsAbstractType &&! type.Type.ExportFields.Contains(defField)))
            {
                continue;
            }
            if (index > 1)
            {
                x.Append(", ");
            }
            x.Append($"{ErlangCommonTemplateExtension.ErlangSnake(defField.Name)} = {f.Apply(this)}");
        }

        x.Append('}');
        return x.ToString();
    }


    protected void Append(List<DType> datas, StringBuilder x)
    {
        x.Append('[');
        int index = 0;
        foreach (var e in datas)
        {
            if (index++ > 0)
            {
                x.Append(',');
            }

            x.Append(e.Apply(this));
        }

        x.Append(']');
    }

    public override string Accept(DArray type)
    {
        var x = new StringBuilder();
        Append(type.Datas, x);
        return x.ToString();
    }

    public override string Accept(DList type)
    {
        var x = new StringBuilder();
        Append(type.Datas, x);
        return x.ToString();
    }

    public override string Accept(DSet type)
    {
        var x = new StringBuilder();
        Append(type.Datas, x);
        return x.ToString();
    }

    public override string Accept(DMap type)
    {
        var x = new StringBuilder();
        x.Append("#{");
        int index = 0;
        foreach (var e in type.Datas)
        {
            if (index++ > 0)
            {
                x.Append(',');
            }

            x.Append($"{e.Key.Apply(this)} => {e.Value.Apply(this)}");
        }

        x.Append('}');
        return x.ToString();
    }
}

